import 'dart:async';
import 'package:flutter/services.dart';

import 'package:flutter_basic/multi_engine/messages.dart';

typedef EventListener = Future<dynamic>? Function(String key, Map arguments);

class SnakeChannel {
  SnakeChannel._();
  static const BasicMessageChannel<Object?> _messageChannel = BasicMessageChannel<Object?>(
      'dev.flutter.multiple-flutters', StandardMessageCodec());
  static  Map<String, Completer<Object?>> _pendingResult = <String, Completer<Object?>>{};
  static const String RESULT_KEY = 'pendingResult';
  static SnakeChannel? _singleton;

  factory SnakeChannel() {
    if (_singleton == null) {
      _singleton = SnakeChannel._();
      _messageChannel.setMessageHandler((message) async{
        if(message is Map){
          print('message:$message');
          Map<String, Object> msgMap = Map<String, Object>.from(message);
          CommonParams commonParams = CommonParams.decode(msgMap);
          print('setMessageHandler:${commonParams.method}');
          switch(commonParams.method){
            case 'onNativeResult':{
              if(_pendingResult.containsKey(RESULT_KEY)){
                Completer completer = _pendingResult[RESULT_KEY]!;
                completer.complete(commonParams.arguments);
                _pendingResult.remove(RESULT_KEY);
              }
            }
              break;


          }
        }else{
          print('message not  Map');
        }

      });
    }
    return _singleton!;
  }

  void sendEventToNative(String key, Map args){
    
  }

  Future<Map<String, dynamic>> getInitialRouteInfo() async {
    var args = CommonParams()
      ..method = 'getInitialRouteInfo';
    final Object param = args.encode();
    var  replyResult = await _messageChannel.send(param) as Map?;
    Map<String, dynamic>? replyMap = (replyResult == null) ? null : Map<String, dynamic>.from(replyResult);

    if(replyMap == null){
      throw PlatformException(
        code: 'channel-error',
        message: 'Unable to establish connection on channel.',
        details: null,
      );
    }
    else if(replyMap['error'] != null){
      throw PlatformException(
        code: '${replyMap['error']}',
        message: 'Unable to establish connection on channel.',
        details: null,
      );
    }
    else{
      print('getInitialRouteInfo: $replyMap');
      Map oriResult = replyMap['result'] as Map;
      Map<String, dynamic> result = Map<String, dynamic>.from(oriResult);
      return result;
    }
  }

  Future<T>? pushNativePage<T extends Object?>(CommonParams args) {
    args.method = 'pushNativePage';
    final Object param = args.encode();
     _messageChannel.send(param);
    final completer = Completer<T>();
    _pendingResult[RESULT_KEY] = completer;
    return completer.future;
  }

  Future<void>? pop<T extends Object?>({CommonParams? args}) {
    if(args == null){
      args = CommonParams();
    }
    args.method = 'pop';
    final Object param = args.encode();
    _messageChannel.send(param);
  }

}